//=============================================================================
//
// I2cTpa81.cpp :
//
// This example shows how to sense the temperature sensor array (thermopile) of
// the I2C thermopile sensor TPA81. After some initialisation the program enters
// a loop updating the measured values for the sensors every 500ms.
//
//-----------------------------------------------------------------------------
// Disclaimer - Exclusion of Liability
//
// This software is distributed in the hope that it will be useful,but WITHOUT 
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
// FITNESS FOR A PARTICULAR PURPOSE. It can be used an modified by anyone
// free of any license obligations or authoring rights.
//=============================================================================

#include "StdAfx.h"
#include <iostream.h>

#define STRMAXLEN   80

HANDLE	fthdl;
DWORD	errCode;
char	ComPortName[STRMAXLEN];
char    LibVersion[STRMAXLEN];
char	ResultStr[STRMAXLEN];

#define INIT_1				 0
#define WAIT_1				 1
#define LOOP_READ_AMB		 2
#define LOOP_READ_AMB_WAIT	 3
#define LOOP_READ_P1		 4
#define LOOP_READ_P1_WAIT	 5
#define LOOP_READ_P2		 6
#define LOOP_READ_P2_WAIT	 7
#define LOOP_READ_P3		 8
#define LOOP_READ_P3_WAIT	 9
#define LOOP_READ_P4		10
#define LOOP_READ_P4_WAIT	11
#define LOOP_READ_P5		12
#define LOOP_READ_P5_WAIT	13
#define LOOP_READ_P6		14
#define LOOP_READ_P6_WAIT	15
#define LOOP_READ_P7		16
#define LOOP_READ_P7_WAIT	17
#define LOOP_READ_P8		18
#define LOOP_READ_P8_WAIT	19
#define LOOP_DISP_RESULT	20

int stage=0;
unsigned short value=0;
unsigned short status=0;
BYTE amb=0;
BYTE p[8]={0,0,0,0,0,0,0,0};
BYTE pidx=255;
int first_time_display=1;

#define DEVADDR 0x68      // I2C address of thermopile sensor TPA81

/*-----------------------------------------------------------------------------
 *  I2c Callback Routine  
 *---------------------------------------------------------------------------*/
void __stdcall cbI2c(I2C_CB * reply)
{
    value = reply->value;
	status = reply->status;

    if(pidx == 128)
    {
        amb = (BYTE)value;
    }
    else if(pidx != 255)
    {
        p[pidx] = (BYTE)value;
    }    

    stage++;
}

/*-----------------------------------------------------------------------------
 *  I2c Access Routines  
 *---------------------------------------------------------------------------*/
static DWORD I2cRead(BYTE devaddr, DWORD offset, BYTE protocol) 
{
	return(ftxI2cRead(fthdl, devaddr, offset, protocol, cbI2c));
}

static DWORD I2cWrite(BYTE devaddr, DWORD offset, WORD data, BYTE protocol) 
{
	return(ftxI2cWrite(fthdl, devaddr, offset, data, protocol, cbI2c));
}

/*-----------------------------------------------------------------------------
 *  DisplayResult  
 *---------------------------------------------------------------------------*/

static void DisplayResult(void)
{
	if(first_time_display)
	{
        sprintf(ResultStr, "      Amb |  P1   P2   P3   P4   P5   P6   P7   P8"); 
		cout << ResultStr << endl;
        sprintf(ResultStr, "      --------------------------------------------"); 
		cout << ResultStr << endl;
		first_time_display = 0;
	}

	switch(status)
	{
		case I2C_SUCCESS:
            sprintf(ResultStr, "\rTemp: %3d | %3d  %3d  %3d  %3d  %3d  %3d  %3d  %3d", 
                                  amb, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
			break;

		case I2C_READ_ERROR:
			sprintf(ResultStr, "\r      I2C_READ_ERROR                              ");
			break;
		
		case I2C_WRITE_ERROR:
			sprintf(ResultStr, "\r      I2C_WRITE_ERROR                             ");
			break;
	}

    cout << ResultStr << flush;
}


/*-----------------------------------------------------------------------------
 *  RunThermopileSensor
 *---------------------------------------------------------------------------*/

static void RunThermopileSensor(void)
{
	DWORD error=0;
	char str_error_stage[32];
	
	stage = INIT_1;

	while(!error && !kbhit())
	{
		switch(stage)
		{
            case INIT_1:
				if(error = I2cRead(DEVADDR, 0x00, 0xA5))
					strcpy(str_error_stage, "INIT_1");
                stage++;
				cout << "Start Loop...(terminate with any key)\n" << endl;
                break;

            case WAIT_1:  
                // waiting for callback
                break;
                
            case LOOP_READ_AMB:    
				if(error = I2cRead(DEVADDR, 0x01, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_AMB");
                pidx = 128;
                stage++;    
                break;

            case LOOP_READ_P1:    
				if(error = I2cRead(DEVADDR, 0x02, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P1");
                pidx = 0;
                stage++;    
                break;

            case LOOP_READ_P2:    
				if(error = I2cRead(DEVADDR, 0x03, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P2");
                pidx = 1;
                stage++;    
                break;

            case LOOP_READ_P3:    
				if(error = I2cRead(DEVADDR, 0x04, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P3");
                pidx = 2;
                stage++;    
                break;

            case LOOP_READ_P4:    
				if(error = I2cRead(DEVADDR, 0x05, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P4");
                pidx = 3;
                stage++;    
                break;

            case LOOP_READ_P5:    
				if(error = I2cRead(DEVADDR, 0x06, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P5");
                pidx = 4;
                stage++;    
                break;

            case LOOP_READ_P6:    
				if(error = I2cRead(DEVADDR, 0x07, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P6");
                pidx = 5;
                stage++;    
                break;

            case LOOP_READ_P7:    
				if(error = I2cRead(DEVADDR, 0x08, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P7");
                pidx = 6;
                stage++;    
                break;

            case LOOP_READ_P8:    
				if(error = I2cRead(DEVADDR, 0x09, 0xA5))
					strcpy(str_error_stage, "LOOP_READ_P8");
                pidx = 7;
                stage++;    
                break;

            case LOOP_READ_AMB_WAIT:    
            case LOOP_READ_P1_WAIT:    
            case LOOP_READ_P2_WAIT:    
            case LOOP_READ_P3_WAIT:    
            case LOOP_READ_P4_WAIT:    
            case LOOP_READ_P5_WAIT:    
            case LOOP_READ_P6_WAIT:    
            case LOOP_READ_P7_WAIT:    
            case LOOP_READ_P8_WAIT:    
                // waiting for callback
                break;
               
			case LOOP_DISP_RESULT:
				DisplayResult();
				Sleep(500);
				stage = LOOP_READ_AMB;
				break;
		}
	}

	if(error)
	{
		char str_error_text[32];

		switch(error)
		{
			case 0xE0005000:
				strcpy(str_error_text, "FTLIB_I2C_INVALID_DEV_ADDR");
				break;
			case 0xE0005001:
				strcpy(str_error_text, "FTLIB_I2C_INVALID_FLAGS_ADDRMODE");
				break;
			case 0xE0005002:
				strcpy(str_error_text, "FTLIB_I2C_INVALID_FLAGS_DATAMODE");
				break;
			case 0xE0005003:
				strcpy(str_error_text, "FTLIB_I2C_INVALID_FLAGS_ERRMODE");
				break;
		}

		cout << "\nRunThermopileSensor: error " << str_error_text << " occured in stage " << str_error_stage << endl << endl;
	}
	else
	{
		cout << "\n\nRunThermopileSensor: User termination" << endl << endl;
	}
}

/*-----------------------------------------------------------------------------
 *  CheckParameter  
 *---------------------------------------------------------------------------*/
static int ChckCOMPar(int argc, char* argv[]) {

    char    *pStr;
    int     comNo;

    if (argc >= 2) {
        if (strlen(argv[1]) > 3) {
            if ((pStr=strstr(argv[1],"COM")) != NULL) {
                sscanf(pStr+3, "%d", &comNo);
                if (comNo >= 1 && comNo <= 255)
                    return 0;
                else {
                    cout << "I2cTpa81.exe: invalid COM number..." << endl << endl;
                    return 1;
                }
            }
        }
    }

    cout << "I2cTpa81.exe: no input given..." << endl << endl;
    return 1;
}


/*-----------------------------------------------------------------------------
 *  main
 *  
 *---------------------------------------------------------------------------*/
int main(int argc, char* argv[]) {

    cout << "\nExample I2cTpa81.exe ..." << endl;

    //  check input paramter
    if (ChckCOMPar(argc,argv)) {
        cout << "Usage: I2cTpa81.exe COMxx\t(e.g. COM2 or COM32)" << endl;
        return 1;
    }

    //  get library version
    ftxGetLibVersionStr(LibVersion, STRMAXLEN);
    cout << "\nftMscLib " << LibVersion << endl; 
    
    //  library initialization
    errCode = ftxInitLib();

    strcpy(ComPortName, argv[1]);
    cout << "\n\nOpen ComPort '" << ComPortName << "' ..." << endl;

    //  open COM port
    fthdl = ftxOpenComDevice(ComPortName, 38400, &errCode);

    if ( errCode == FTLIB_ERR_SUCCESS ) {

        cout << "Connected to ROBO TX Controller ..." << endl;

        //  starting transferarea
        errCode = ftxStartTransferArea(fthdl);

        if ( errCode == FTLIB_ERR_SUCCESS) {

            cout << "TransferArea was started and runs..." << endl;

			RunThermopileSensor();

            //  stop TransferArea
            ftxStopTransferArea(fthdl);
        }

        else {
            //  error case
            cout << "Error: TransferArea was not started !" << endl << endl;
        }

        //  closing port and library
        cout << "Closing ComPort '" << ComPortName << "' ..." << endl;
	    errCode = ftxCloseDevice(fthdl);
    }

    else {
        //  error case
        cout << "Error: No interface available (Port '" << ComPortName << "')" << endl;
    }

    //  close library
    ftxCloseLib();

    return 0;
}
